Re: syslog()/snprintf(): beware of functions with fuzzy specs

Casper Dik (casper@Holland.Sun.COM)
Wed, 6 Sep 1995 16:39:10 +0200

>BSD4.4 snprintf()s return the number of characters they would have
>written had the buffer been infinite.  This is despite the manual page
>saying they return the number of characters actually written.

This should be fixed.  It requires the *snprintf() code to parse
and examine all arguments: that isn't necessary.

And p += snprintf(p, &buf[sizeof(buf)] -p, ...)
won't work as expected.

>Number of characters written does not include the NULL.

(Aside: I prefer NUL to refer to '\0' and NULL to refer to the null pointer)

>GNU snprintf()s return the number of characters actually written (minus
>the NULL).  On a overflowed buffer, the GNU documentation conflicts with
>itself.  At one point it says, (bufsiz - 1) is returned, and in another
>example it says (bufsiz) is returned (but (bufsiz - 1) plus a NULL
>character are written).  I'm not sure what it does for real.

I'm pretty sure we want a terminated string.  I.e., return "bufsiz - 1".

>I've seen a few other cobbled version of *nprintf.  I'm best off with a
>dart board if I needed to apriori determine what they do on the boundary
>cases.
>
>Some important boundary cases:
>
>vsnprintf (buf, bufsiz, fmt, ap)
>
>  bufsiz = 0
>  bufsiz = 1
>  bufsiz = amount of chars sprint will use, less one for the null
>  bufsiz = amount of chars sprint will use, no room for null
>  bufsiz = less than amount of chars sprint will use
>
>Which return values of -1, 0, bufsiz - 1, bufsiz, or >bufsiz (heaven
>forbid a core dump)?  Do they write on buf[bufsiz]?  What do they write
>to buf?  What is the state of NULL terminatation on each of the
>sitations above?  Many different answers have I seen.

snsprintf should never write buf[bufsize], it can write buf[bufsize-1].

I prefer the following:

        bufsiz          strsize                 return value
         0               N/A                     0  (can argue in favour of -1)
         1               N/A                     0
         >1              <bufsiz                 strsize
         >1              >=bufsiz                bufsiz-1

It can be argued that snprintf(buf, 0, ...) should return -1: there's
no room for the '\0'.

But you also want p += snprintf(....) to continue to work.

(But note that if you do that properly, the remaining number of bytes
will never drop below 1)

>For those of you working on syslog patches using *nprintf, you will do
>the world a favor if you make it explicitly clear the semantics you
>expect.

Or ignore the return value and use strlen().  (In which case you
depend on snprintf to return '\0' terminated strings.)

Casper